/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.txweb.interceptor;


import com.jspx.boot.sign.*;
import com.jspx.txweb.support.MultipartSupport;
import com.jspx.utils.DateUtil;
import org.slf4j.Logger;
import com.jspx.boot.environment.Environment;
import org.slf4j.LoggerFactory;
import com.jspx.json.JSONObject;
import com.jspx.sioc.annotation.Ref;
import com.jspx.txweb.ActionInvocation;
import com.jspx.txweb.ActionProxy;
import com.jspx.txweb.IRole;
import com.jspx.txweb.IUserSession;
import com.jspx.txweb.dao.PermissionDAO;
import com.jspx.txweb.env.TXWebIoc;
import com.jspx.txweb.online.OnlineManager;
import com.jspx.txweb.support.ActionSupport;
import com.jspx.txweb.table.MemberRole;
import com.jspx.txweb.table.Role;
import com.jspx.txweb.util.TXWebUtil;
import com.jspx.utils.ArrayUtil;
import com.jspx.utils.ClassUtil;
import com.jspx.utils.StringUtil;
import java.util.Date;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: chenYuan
 * Date: 2010-11-11
 * Time: 13:50:12
 * 权限拦截 ,规则为,在admin目录下的action必须大于等于操作人员,并且放入用户的信息和角色信息,适用cms 类型软件
 */

public class PermissionInterceptor extends InterceptorSupport {
    private static final Logger log = LoggerFactory.getLogger(PermissionInterceptor.class);
    private String roleClass = Role.class.getName();
    private static final JSONObject multipartSupportErrorJson = new JSONObject();

    public PermissionInterceptor()
    {
        multipartSupportErrorJson.put("repair", false);
        multipartSupportErrorJson.put("success", 0);
        multipartSupportErrorJson.put("error", 1);
        multipartSupportErrorJson.put("OK", 0);
        multipartSupportErrorJson.put("state", "error");
        multipartSupportErrorJson.put("thumbnail", 0);
        multipartSupportErrorJson.put(Environment.id_message, "need login,no authority");
    }

    public void init() {

    }

    public void destroy() {

    }

    public String getRoleClass() {
        return roleClass;
    }

    public void setRoleClass(String roleClass) {
        this.roleClass = roleClass;
    }

    private boolean permission = true;
    public void setPermission(boolean permission) {
        this.permission = permission;
    }

    //办公方式
    private boolean office = false;

    public boolean isOffice() {
        return office;
    }

    public void setOffice(boolean office) {
        this.office = office;
    }

    /**
     * 载入在线管理
     */
    private OnlineManager onlineManager;
    @Ref(name = Environment.onlineManager,test = true)
    public void setOnlineManager(OnlineManager onlineManager) {
        this.onlineManager = onlineManager;
    }

    private PermissionDAO permissionDAO;
    @Ref(name = TXWebIoc.permissionDAO,test = true)
    public void setPermissionDAO(PermissionDAO permissionDAO) {
        this.permissionDAO = permissionDAO;
    }

    /**
     * 登陆页面入口必须排除
     */
    private String[] ruleOutUrl;
    public void setRuleOutUrl(String[] ruleOutUrl) {
        this.ruleOutUrl = ruleOutUrl;
    }

    /**
     * 游客不允许方式的页面列表
     */
    private String[] guestStopUrl;

    public String[] getGuestStopUrl() {
        return guestStopUrl;
    }

    public void setGuestStopUrl(String[] guestStopUrl) {
        this.guestStopUrl = guestStopUrl;
    }

    /**
     * 管理登陆目录 为 manage, admin 交给程序自己管理
     */
    private String manageFolder = "manage";
    public void setManageFolder(String manageFolder) {
        this.manageFolder = manageFolder;
    }

    public String intercept(ActionInvocation actionInvocation) throws Exception {
        //这里是不需要验证的action
        ActionProxy actionProxy = actionInvocation.getActionProxy();
        ActionSupport action = actionProxy.getAction();
        IUserSession userSession = onlineManager.getUserSession(action);

        String method = StringUtil.isNULL(actionProxy.getMethod())? TXWebUtil.defaultExecute:actionProxy.getMethod();
        String namespace = action.getEnv(ActionSupport.Key_Namespace);
        String actionName = actionInvocation.getActionName();
        log.debug("intercept call namespace:" + namespace + "  actionName:" + actionName + "  method:" + method);
        //登陆入口，直接放行
        if (ArrayUtil.inArray(ruleOutUrl, "/" + namespace + "/" + actionName, true))
        {
            return actionInvocation.invoke();
        }

        //自动分配调试权限 begin
        if (!permission && (Environment.SYSTEM_ID==userSession.getUid()||userSession.getUid()==1))
        {
            //调试模式
            Role role = createDebugRole();
            role.setNamespace(permissionDAO.getNamespace());
            role.setIp(userSession.getIp());
            userSession.setRole(role);
        }
        //自动分配测试权限 end
        action.put(ActionSupport.Key_UserSession, userSession);
        //没有角色权限自动载入 begin
        if (action.isGuest())
        {
            userSession.setRole(permissionDAO.getRole(config.getInt(Environment.guestRole)));
            //屏蔽的URL游客
            if (!ActionSupport.LOGIN.equals(actionName) &&  ArrayUtil.inArray(guestStopUrl, actionInvocation.getActionName(), true)) {
                action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needLogin));
                if (actionProxy.getCallJson()!=null)
                {
                    TXWebUtil.print(language.getLang(LanguageRes.needLogin),TXWebUtil.jsonType,action.getResponse());
                } else
                {
                    TXWebUtil.print(language.getLang(LanguageRes.needLogin),TXWebUtil.jsonType,action.getResponse());
                }
                return ActionSupport.LOGIN;
            }
        } else if (userSession.getRole(permissionDAO.getNamespace()).getId() <= 0) {

            List<MemberRole> roles = permissionDAO.getMemberRoles(userSession.getUid());
            if (!roles.isEmpty())
            {
                for (MemberRole memberRole : roles) {
                    userSession.setRole(memberRole.getRole());
                }
            }
            //二次修复
            if (userSession.getRole(permissionDAO.getNamespace()).getId() <= 0) {
                Role role = permissionDAO.getRole(config.getInt(Environment.registerRole));
                if (role.getId()>0)
                {
                    MemberRole memberRole = new MemberRole();
                    memberRole.setRoleId(role.getId());
                    memberRole.setRole(role);
                    memberRole.setUid(userSession.getUid());
                    memberRole.setNamespace(permissionDAO.getNamespace());
                    log.info(permissionDAO.getNamespace() +" member " +  userSession.getName() + " auto bind role " + role.getId() + " save " + permissionDAO.save(memberRole));
                }
            }
        }
        //没有角色权限自动载入 end

        //如果都载入为空，那么载入游客权限 begin
        if (permission&&userSession.getRole(permissionDAO.getNamespace()).getId() == 0) {
            log.info(permissionDAO.getNamespace() +" need to config role");
        }
        //如果都载入为空，那么载入游客权限 end

        IRole role = userSession.getRole(permissionDAO.getNamespace());
        if (role==null)
        {
            log.info(permissionDAO.getNamespace() +" role need init,角色没有初始化配置");
            return ActionSupport.LOGIN;
        }

        //访问控制,放开登录和管理目录
        if (!manageFolder.equalsIgnoreCase(namespace)&&(role.getUserType()<UserType.INTENDANT)&&!ArrayUtil.inArray(new String[]{ActionSupport.ERROR,ActionSupport.UNTITLED,ActionSupport.LOGIN},actionName,true))
        {
            //站点关闭 begin
            if (permission&&!config.getBoolean(Environment.openSite)) {
                String closeInfo = config.getString(Environment.closeInfo);
                if (StringUtil.isNULL(closeInfo)) closeInfo = action.getRootNamespace() + "关闭状态，不允许访问";
                TXWebUtil.errorPrint(closeInfo,action.getResponse(), HttpStatusType.HTTP_status_500);
                return ActionSupport.NONE;
            }
            //站点关闭 end
            //游客访问控制 begin
            if (!config.getBoolean(Environment.useGuestVisit)&&role.getUserType()<=UserType.NONE) {
                //不输出信息就会到登录页面
                String closeInfo = config.getString(Environment.closeGuestVisitInfo);

                if (actionProxy.getCallJson()!=null)
                {
                     JSONObject errorInfo = TXWebUtil.createRocErrorInfo(actionName, ErrorRocCode.need_login,language.getLang(LanguageRes.needLogin));
                     errorInfo.put(Environment.SUCCESS,0);
                     errorInfo.put(Environment.message,language.getLang(LanguageRes.needLogin));
                     TXWebUtil.print(errorInfo.toString(4),TXWebUtil.jsonType,action.getResponse());
                } else
                {
                    if (StringUtil.isNULL(closeInfo))
                    {
                        return ActionSupport.LOGIN;
                    }
                    else TXWebUtil.print(closeInfo,TXWebUtil.htmlType,action.getResponse());
                }
                return ActionSupport.NONE;
            }
            //游客访问控制 end

            //时段限制 begin
            String accessForbiddenRange = config.get(Environment.accessForbiddenRange);
            if (!StringUtil.isNULL(accessForbiddenRange) && DateUtil.isInTimeExpression(new Date(), accessForbiddenRange)) {
                String accessForbiddenTip = config.getString(Environment.accessForbiddenTip);
                if (StringUtil.isNULL(accessForbiddenTip))
                    accessForbiddenTip = accessForbiddenRange + "时间段内不能访问";
                TXWebUtil.print(accessForbiddenTip,TXWebUtil.htmlType,action.getResponse());
                return ActionSupport.NONE;
            }
            //时段限制end

        }

        if (permission) {
            /*
             *        readUrl:'/user/config/read.${suffix}',
             *        writeUrl:'/user/config/write.${suffix}'
             */
            //个人配置部分，登陆后就能访问
            if ("user/config".equals(namespace) && userSession.isGuest())
            {
                //用户个人配置部分必须要求登陆
                action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needLogin));
                return ActionSupport.LOGIN;
            }

            //管理目录，如果是游客就要求登录
            if (manageFolder.equals(namespace))
            {
                if (userSession.isGuest())
                {
                    action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needLogin));
                    return ActionSupport.LOGIN;
                }
                if (role.getUserType()<UserType.INTENDANT )
                {
                    action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needPermission));
                    return ActionSupport.LOGIN;
                }
                return actionInvocation.invoke();
            }

            if (role.getUserType() < UserType.INTENDANT)
            {
                if (office && role.getOfficeType() == YesNoType.NO)
                {
                    //会员进入后，判断如果是办公模式，非工作人员都要求登陆，成为工作人员才能访问
                    action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needOfficeWorkers));
                    if (action instanceof MultipartSupport)
                    {
                        action.setResult(multipartSupportErrorJson);
                        action.setActionResult(ActionSupport.ROC);
                        return ActionSupport.ROC;
                    }
                    return ActionSupport.LOGIN;
                }

                if (!role.checkOperate(namespace,actionName,method))
                {
                    //会员进入后，正常模式，完全通过后台权限判断是否能够操作
                    action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needPermission) + ", role name :" + role.getName() + " for " + role.getNamespace());
                    if (action instanceof MultipartSupport)
                    {
                        action.setResult(multipartSupportErrorJson);
                        action.setActionResult(ActionSupport.ROC);
                        return ActionSupport.ROC;
                    }
                    return ActionSupport.UNTITLED;
                }
            }

            //角色权限表判断
            if (role.getUserType() >= UserType.INTENDANT&&StringUtil.hasLength(method) && role.getUserType() < UserType.ADMINISTRATOR &&!role.checkOperate(namespace,actionName, method))
            {
                if (StringUtil.isNULL(role.getPermission())) permissionDAO.evict(ClassUtil.loadClass(roleClass));
                if (role.getId() == 0) {
                    action.addFieldInfo(Environment.warningInfo, role.getName() + language.getLang(LanguageRes.notLogin));
                    if (action instanceof MultipartSupport)
                    {
                        action.setResult(multipartSupportErrorJson);
                        action.setActionResult(ActionSupport.ROC);
                        return ActionSupport.ROC;
                    }
                    return ActionSupport.LOGIN;
                } else {

                    action.addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.needPermission) + "," + role.getName()+ ", to config action");
                    if (action instanceof MultipartSupport)
                    {
                        action.setResult(multipartSupportErrorJson);
                        action.setActionResult(ActionSupport.ROC);
                        return ActionSupport.ROC;
                    }
                    return ActionSupport.UNTITLED;
                }
            }
        }
        //执行下一个动作,可能是下一个拦截器,也可能是action取决你的配置
        return actionInvocation.invoke();
        //也可以 return Action.ERROR; 终止action的运行
    }

}